package com.itasura.annot.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * @author sailor wang
 * @date 2018/11/15 5:34 PM
 * @description
 */
@Slf4j
@Aspect
@Component
public class LoginAspect {

    @Pointcut("@annotation(com.itasura.annot.annotation.LoginAnnotation)")
    public void login() {
    }

    /**
     * 前置增强
     *
     * @param joinPoint
     */
    @Before("login()")
    public void doBefore(JoinPoint joinPoint) {
        log.info("前置增强器, JoinPoint类提供了方法的各种信息，包括目标对象，签名，代理方法，参数等");
        log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
    }

    /**
     * 后置返回增强（目标方法只要执行完了返回后执行后置增强）
     *
     * @param joinPoint
     * @param ret
     */
    @AfterReturning(value = "login()", returning = "ret")
    public void doAfterReturn(JoinPoint joinPoint, Object ret) {
        log.info("后置返回增强");
        log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));

        log.info("返回参数 ret -> {}", ret.toString());

    }

    /**
     * 异常通知：目标方法发生异常的时候执行以下代码
     */
    @AfterThrowing(value = "login()", throwing = "e")
    public void afterThorwingMethod(JoinPoint jp, NullPointerException e) {
        String methodName = jp.getSignature().getName();
        log.info("【异常通知】the method 【" + methodName + "】 occurs exception: ", e);
    }

    /**
     * 环绕通知：目标方法执行前后分别执行一些代码，发生异常的时候执行另外一些代码
     *
     * @return
     */
    @Around(value = "login()")
    public Object aroundMethod(ProceedingJoinPoint jp) {
        String methodName = jp.getSignature().getName();
        Object result = null;
        try {
            log.info("【环绕通知中的--->前置通知】：the method 【" + methodName + "】 begins with " + Arrays.asList(jp.getArgs()));
            //执行目标方法
            result = jp.proceed();
            log.info("【环绕通知中的--->返回通知】：the method 【" + methodName + "】 ends with " + result);
        } catch (Throwable e) {
            log.info("【环绕通知中的--->异常通知】：the method 【" + methodName + "】 occurs exception " ,e);
        }

        log.info("【环绕通知中的--->后置通知】：-----------------end.----------------------");
        return result;
    }

    /**
     * 后置最终增强（目标方法只要执行完了就会执行后置增强）
     *
     * @param joinPoint
     */
    @After("login()")
    public void doAfter(JoinPoint joinPoint) {
        // 获取request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        log.info("获取request 可用于记录用户登录日志。。。。");
        log.info("后置最终增强");
        log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
    }


}